<?php

Raise::load('core.RaiseObject');

/**
 * RaiseStream abstract class
 * Provides abstraction for a stream
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core.IO
 * @abstract
 * @since 1.2
 */
abstract class RaiseStream extends RaiseObject {

    /**
     * The PHP resource handle that is associated with this stream
     * @var resource
     */
    protected $handle = null;

    /**
     * The parent RaiseStream that this RaiseStream wraps around
     * @var RaiseStream
     */
    protected $parentStream = null;

    /**
     * The pointer position of this RaiseStream
     * @var integer
     */
    protected $position = 0;

    /**
     * Get the length of the stream
     * @return integer
     * @abstract
     */
    public abstract function length();

    /**
     * Determine if the seek operation can be done on the stream
     * @return boolean
     * @abstract
     */
    public abstract function isSeekable();

    /**
     * Determine if the stream can be read
     * @return boolean
     * @abstract
     */
    public abstract function isReadable();

    /**
     * Determine if the stream can be written
     * @return boolean
     * @abstract
     */
    public abstract function isWriteable();

    /**
     * Close the stream and free up resources
     * @abstract
     */
    public abstract function close();

    /**
     * Read a string from the stream starting from the pointer position and move the pointer by $length
     * @param int $length The number of bytes to read from the stream
     * @return string The string value from the stream
     * @abstract
     */
    public abstract function read($length);

    /**
     * Read a single byte from the stream starting from the pointer position and move the pointer by 1
     * @return int The value of the byte
     * @abstract
     */
    public abstract function readByte();

    /**
     * Write a string to the stream at the pointer location and move the pointer by length of $str
     * @param string $str The string value
     * @abstract
     */
    public abstract function write($str);

    /**
     * Write a single byte to the stream at the pointer location and move the pointer by 1
     * @param integer $i A byte value from 0-255
     * @abstract
     */
    public abstract function writeByte($i);

    /**
     * Move the pointer location to a specific location
     * @param integer $position The new position of the pointer
     * @abstract
     */
    public abstract function seek($position);

    /**
     * Get or set the position of the pointer. Internal method.
     * @param integer $p (optional) The new position to set to
     * @return integer
     */
    public function position($p = null){
        if(func_num_args() == 1){
            $this->position = $p;
        }
        return $this->position;
    }

    /**
     * Copy the data of one stream to another.
     * Note that calling this method will eventually set both streams' pointer position
     * to the end of the stream.
     * @param RaiseStream $stream
     */
    public function copy($stream){
        if($this->isSeekable() && $stream->isSeekable()){
            $this->seek(0);

            $buff = '';
            $stream->seek(0);
            while($buff = $this->read(4096)){
                $stream->write($buff);
            }
        }
    }

}

